package Q6_10_Test_Strips; import java.util.ArrayList; import java.util.HashSet; import java.util.Random; public class QuestionB { public static ArrayList<Bottle> createBottles(int nBottles, int poisoned) { ArrayList<Bottle> bottles = new ArrayList<Bottle>(); for (int i = 0; i < nBottles; i++) { bottles.add(new Bottle(i)); } if (poisoned == -1) { Random random = new Random(); poisoned = random.nextInt(nBottles); } bottles.get(poisoned).setAsPoisoned(); System.out.println("Added poison to bottle " + poisoned); return bottles; } public static int findPoisonedBottle(ArrayList<Bottle> bottles, ArrayList<TestStrip> strips) { if (bottles.size() > 1000 || strips.size() < 10) return -1; int tests = 4; // three digits, plus one extra int nTestStrips = strips.size(); /* Run tests. */ for (int day = 0; day < tests; day++) { runTestSet(bottles, strips, day); } /* Get results. */ HashSet<Integer> previousResults = new HashSet<Integer>(); int[] digits = new int[tests]; for (int day = 0; day < tests; day++) { int resultDay = day + TestStrip.DAYS_FOR_RESULT; digits[day] = getPositiveOnDay(strips, resultDay, previousResults); previousResults.add(digits[day]); } /* If day 1's results matched day 0's, update the digit. */ if (digits[1] == -1) { digits[1] = digits[0]; } /* If day 2 matched day 0 or day 1, check day 3. Day 3 is * the same as day 2, but incremented by 1. */ if (digits[2] == -1) { if (digits[3] == -1) { /* Day 3 didn't give new result */ /* Digit 2 equals digit 0 or digit 1. But, digit 2, when incremented also matches * digit 0 or digit 1. This means that digit 0 incremented matches digit 1, or the * other way around. */ digits[2] = ((digits[0] + 1) % nTestStrips) == digits[1] ? digits[0] : digits[1]; } else { digits[2] = (digits[3] - 1 + nTestStrips) % nTestStrips; } } return digits[0] * 100 + digits[1] * 10 + digits[2]; } /* Run set of tests for this day. */ public static void runTestSet(ArrayList<Bottle> bottles, ArrayList<TestStrip> strips, int day) { if (day > 3) return; // only works for 3 days (digits) + one extra for (Bottle bottle : bottles) { int index = getTestStripIndexForDay(bottle, day, strips.size()); TestStrip testStrip = strips.get(index); testStrip.addDropOnDay(day, bottle); } } /* Get test strip index that should be used on this bottle on this day. */ public static int getTestStripIndexForDay(Bottle bottle, int day, int nTestStrips) { int id = bottle.getId(); switch (day) { case 0: return id /100; case 1: return (id % 100) / 10; case 2: return id % 10; case 3: return (id % 10 + 1) % nTestStrips; default: return -1; } } /* Get results that are positive for a particular day, excluding prior results. */ public static int getPositiveOnDay(ArrayList<TestStrip> testStrips, int day, HashSet<Integer> previousResults) { for (TestStrip testStrip : testStrips) { int id = testStrip.getId(); if (testStrip.isPositiveOnDay(day) && !previousResults.contains(id)) { return testStrip.getId(); } } return -1; } public static ArrayList<TestStrip> createTestStrips(int nTestStrips) { ArrayList<TestStrip> testStrips = new ArrayList<TestStrip>(); for (int i = 0; i < nTestStrips; i++) { testStrips.add(new TestStrip(i)); } return testStrips; } public static void main(String[] args) { int nBottles = 1000; int nTestStrips = 10; for (int poisoned = 0; poisoned < nBottles; poisoned++) { ArrayList<Bottle> bottles = createBottles(nBottles, poisoned); ArrayList<TestStrip> testStrips = createTestStrips(nTestStrips); int poisonedId = findPoisonedBottle(bottles, testStrips); System.out.println("Suspected Bottle: " + poisonedId); if (poisonedId != poisoned) { System.out.println("ERROR"); break; } } } }